Skip to content

feat(gmail,outlook): add track_delivery with consistent tracking IDs#112

Merged
dimavedenyapin merged 10 commits intomainfrom
feature/gmail-track-delivery
Mar 29, 2026
Merged

feat(gmail,outlook): add track_delivery with consistent tracking IDs#112
dimavedenyapin merged 10 commits intomainfrom
feature/gmail-track-delivery

Conversation

@dimavedenyapin
Copy link
Copy Markdown

@dimavedenyapin dimavedenyapin commented Mar 26, 2026

Summary

  • Adds optional track_delivery boolean parameter to both Gmail and Outlook send_email tools
  • When true, both return the same JSON shape for downstream delivery tracking:
    { "status": "sent", "tracking_message_id": "...", "tracking_thread_id": "..." }
  • Gmail: tracking_message_id = Gmail message ID, tracking_thread_id = Gmail threadId
  • Outlook: Uses draft-then-send flow (POST /me/messagesPOST /me/messages/{id}/send) to capture the message ID and conversationId before sending
  • Backward compatible — existing calls without track_delivery are unaffected

Test plan

  • Gmail: existing test_send_email test passes (no track_delivery = old behavior)
  • Gmail: call send_email with track_delivery: true → verify JSON with tracking_message_id, tracking_thread_id
  • Outlook: call send_email without track_delivery → same "Email sent successfully" text
  • Outlook: call send_email with track_delivery: true → verify draft-then-send returns tracking JSON
  • Outlook: verify draft is actually sent (check Sent Items folder)

🤖 Generated with Claude Code

dimavedenyapin and others added 2 commits March 26, 2026 23:12
When track_delivery=true, returns structured JSON with messageId, threadId,
labelIds, and recipient info instead of plain text — enables delivery tracking
in workflow-builder's McpToolNode without requiring a separate Gmail send node.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…s Gmail and Outlook

Gmail: returns tracking_message_id (Gmail message id) and tracking_thread_id (threadId)
Outlook: uses draft-then-send flow when track_delivery=true to capture message id
  and conversationId before sending, returns same tracking_message_id/tracking_thread_id shape

Both providers return identical JSON shape:
  { "status": "sent", "tracking_message_id": "...", "tracking_thread_id": "..." }

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@dimavedenyapin dimavedenyapin changed the title feat(gmail): add track_delivery param to send_email feat(gmail,outlook): add track_delivery with consistent tracking IDs Mar 27, 2026
dimavedenyapin and others added 7 commits March 27, 2026 09:14
Both Gmail and Outlook send_email now return:
  { "status": "sent", "channelMessageId": "..." }

This maps directly to workflo's messages.channel_message_id column,
which the AddConversationMessageNode uses to store the external message ID.

Dropped tracking_thread_id — workflo uses sessionId (managed by the
workflow), not provider-side thread/conversation IDs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Both send_email tools now return conversationId alongside channelMessageId
when track_delivery is true. Gmail maps threadId → conversationId, Outlook
returns its native conversationId from the draft.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Gmail: calls users().watch() with GMAIL_PUBSUB_TOPIC env var on each
tracked send (idempotent, safe to repeat). Watches SENT + INBOX labels.

Outlook: checks for existing Graph subscription before creating one.
Uses OUTLOOK_WEBHOOK_URL env var. Subscription covers me/messages with
created+updated change types, max 4230-minute expiry.

Both are non-blocking — failures are logged but don't prevent the
email send or tracking response.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wire both env vars into stage and production deploy workflows via
GitHub vars (INT_/PROD_ prefixed). Also add to .env.example for
local development reference.

These are optional — watch/webhook setup is skipped when unset.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Apply black formatter to src/servers/gmail/main.py and
src/servers/outlook/main.py to pass the format-check CI job.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
These files were unintentionally changed — .dockerignore was deleted
and remote.py had debug=True hardcoded + server names exposed in
health checks. Restoring both to their state on main.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The Graph object ID changes when a message moves from Drafts to Sent
Items after send. internetMessageId (RFC 2822 Message-ID header) is
stable across this transition, so webhook notifications can be matched
back to the sent message in our DB.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Comment thread src/servers/gmail/main.py Outdated
Comment thread src/servers/outlook/main.py Outdated
…_delivery

Gmail: structured JSON with channelMessageId/conversationId is now always
returned. track_delivery only controls whether Gmail Watch (Pub/Sub) is set up.

Outlook: always uses draft-then-send flow (since /me/sendMail returns 202 with
empty body). track_delivery only controls webhook subscription setup.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@dimavedenyapin dimavedenyapin merged commit be755f5 into main Mar 29, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant